home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue54 / System / FileSysDemo / UFileSys.pas < prev   
Encoding:
Pascal/Delphi Source File  |  2000-01-07  |  23.0 KB  |  704 lines

  1. unit UFileSys;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls, Grids, ExtCtrls;
  8.  
  9. type
  10.   TForm1 = class(TForm)
  11.     DriveList: TComboBox;
  12.     Label1: TLabel;
  13.     VolSize: TLabel;
  14.     VolName: TLabel;
  15.     FSystem: TLabel;
  16.     SerNum: TLabel;
  17.     DrvType: TLabel;
  18.     FreeSp: TLabel;
  19.     Bevel1: TBevel;
  20.     FolderList: TComboBox;
  21.     Label2: TLabel;
  22.     Label16: TLabel;
  23.     CurFolder: TEdit;
  24.     GroupBox1: TGroupBox;
  25.     cbHidden: TCheckBox;
  26.     cbSystem: TCheckBox;
  27.     cbReadOnly: TCheckBox;
  28.     cbArchive: TCheckBox;
  29.     FileList: TListBox;
  30.     FileCount: TLabel;
  31.     TotFileSize: TLabel;
  32.     Button1: TButton;
  33.     Bevel2: TBevel;
  34.     Label3: TLabel;
  35.     WatchDirName: TEdit;
  36.     WatchSubs: TCheckBox;
  37.     StartButton: TButton;
  38.     StopButton: TButton;
  39.     Bevel3: TBevel;
  40.     Bevel4: TBevel;
  41.     procedure FormCreate(Sender: TObject);
  42.     procedure FormDestroy(Sender: TObject);
  43.     procedure DriveListChange(Sender: TObject);
  44.     procedure FolderListChange(Sender: TObject);
  45.     procedure CurFolderKeyPress(Sender: TObject; var Key: Char);
  46.     procedure cbReadOnlyClick(Sender: TObject);
  47.     procedure Button1Click(Sender: TObject);
  48.     procedure WatchDirNameChange(Sender: TObject);
  49.     procedure StartButtonClick(Sender: TObject);
  50.     procedure StopButtonClick(Sender: TObject);
  51.     procedure WatchDirNameKeyPress(Sender: TObject; var Key: Char);
  52.   private
  53.     { Private declarations }
  54.     DirSize: TLargeInteger;
  55.     procedure WatchDirChanged (Sender: TObject; CurrentFolder: Boolean);
  56.     function FormatBigBytes (const Msg: String; Value: TLargeInteger): String;
  57.     procedure UpdateFolderList (const FolderName: String);
  58.     procedure SumProc (const Name: String; const Info: TSearchRec; var Continue: Boolean);
  59.   public
  60.     { Public declarations }
  61.   end;
  62.  
  63. var
  64.   Form1: TForm1;
  65.  
  66. implementation
  67.  
  68. {$R *.DFM}
  69.  
  70. type
  71.     EFileSystem = class (Exception);
  72.  
  73.     TDriveType  = ( fsUnknown, fsNoRoot, fsRemovable, fsFixed, fsRemote, fsCDROM, fsRAMDisk );
  74.     TDriveTypes = set of TDriveType;
  75.  
  76.     TFileType   = ( ftReadOnly, ftHidden, ftSystem, ftArchive );
  77.     TFileTypes  = set of TFileType;
  78.  
  79.     TWalkProc = procedure (const Name: String; const Info: TSearchRec; var Continue: Boolean) of Object;
  80.     TWatchDirProc = procedure (Sender: TObject; CurrentFolder: Boolean) of Object;
  81.  
  82.     TFileSystem = class;
  83.  
  84.     TWatchThread = class (TThread)
  85.     private
  86.         fOwner: TFileSystem;
  87.         fNotifyHandle: THandle;
  88.     protected
  89.         procedure Execute; override;
  90.     public
  91.         constructor Create (AOwner: TFileSystem);
  92.         destructor Destroy; override;
  93.     end;
  94.  
  95.     TFileSystem = class (TComponent)
  96.     private
  97.         fDriveLetter: Char;
  98.         fSerialNumber: DWord;
  99.         fDriveType: TDriveType;
  100.         fDriveTypes: TDriveTypes;
  101.         fFileTypes: TFileTypes;
  102.         fFolders: TStringList;
  103.         fFiles: TStringList;
  104.         fFolderName: String;
  105.         fWatchDirectory: String;
  106.         fWatchSubtree: Boolean;
  107.         fWatchThread: TWatchThread;
  108.         fWatchMask: Integer;
  109.         fOnWatchDirChange: TWatchDirProc;
  110.         fFileSystem, fDrives, fVolumeName: String;
  111.         fTotalSize, fTotalFileSize, fAvailableSpace, fFreeSpace: TLargeInteger;
  112.         procedure FileWalker (const Folder: String; Proc: TWalkProc; var Continue: Boolean);
  113.         procedure FolderWalker (const Folder: String; Proc: TWalkProc; var Continue: Boolean);
  114.         procedure InitDrivesList;
  115.         procedure RefreshFolderAndFileList;
  116.         function GetDriveCount: Integer;
  117.         function GetIsReady: Boolean;
  118.         procedure SignalFileNotification;
  119.         function MatchingFile (Rec: TSearchRec): Boolean;
  120.         procedure SetDriveLetter (Value: Char);
  121.         function GetDriveChar (Index: Integer): Char;
  122.         function GetUsedSpace: TLargeInteger;
  123.         function GetSerialNumber: String;
  124.         procedure SetFolderName (Value: String);
  125.         procedure SetVolumeName (Value: String);
  126.         procedure SetDriveTypes (Value: TDriveTypes);
  127.         procedure SetFileTypes (Value: TFileTypes);
  128.         procedure SetWatchDirectory (const DirName: String);
  129.     public
  130.         constructor Create (AOwner: TComponent); override;
  131.         destructor Destroy; override;
  132.         procedure Refresh;
  133.         procedure TreeWalkFiles (Proc: TWalkProc);
  134.         procedure TreeWalkFolders (Proc: TWalkProc);
  135.         class function DirectoryExists (const DirName: String): Boolean;
  136.         property Drives [Index: Integer]: Char read GetDriveChar;
  137.         property Folders: TStringList read fFolders;
  138.         property Files: TStringList read fFiles;
  139.     published
  140.         // File-specific stuff
  141.         property TotalFileSize: TLargeInteger read fTotalFileSize;
  142.         property FileTypes: TFileTypes read fFileTypes write SetFileTypes default [ftArchive];
  143.         // Folder-specific stuff
  144.         property FolderName: String read fFolderName write SetFolderName;
  145.         // Drive-specific stuff....
  146.         property DriveLetter: Char read fDriveLetter write SetDriveLetter;
  147.         property DriveType: TDriveType read fDriveType;
  148.         property IsReady: Boolean read GetIsReady;
  149.         property VolumeName: String read fVolumeName write SetVolumeName;
  150.         property FileSystem: String read fFileSystem;
  151.         property SerialNumber: String read GetSerialNumber;
  152.         property SerialNum: DWord read fSerialNumber;
  153.         property TotalSize: TLargeInteger read fTotalSize;
  154.         property FreeSpace: TLargeInteger read fFreeSpace;
  155.         property UsedSpace: TLargeInteger read GetUsedSpace;
  156.         property AvailableSpace: TLargeInteger read fAvailableSpace;
  157.         property DriveCount: Integer read GetDriveCount;
  158.         property DriveTypes: TDriveTypes read fDriveTypes write SetDriveTypes default [fsFixed];
  159.         // Directory-watching stuff
  160.         property WatchDirectory: String read fWatchDirectory write SetWatchDirectory;
  161.         property WatchSubtree: Boolean read fWatchSubtree write fWatchSubtree default False;
  162.         property WatchMask: Integer read fWatchMask write fWatchMask default File_Notify_Change_File_Name or File_Notify_Change_Dir_Name;
  163.         property OnWatchDirChange: TWatchDirProc read fOnWatchDirChange write fOnWatchDirChange;
  164.     end;
  165.  
  166. { TWatchThread }
  167.  
  168. constructor TWatchThread.Create (AOwner: TFileSystem);
  169. begin
  170.     Inherited Create (True);
  171.     fOwner := AOwner;
  172.     Priority := tpLower;
  173.     Suspended := False;
  174. end;
  175.  
  176. destructor TWatchThread.Destroy;
  177. begin
  178.     if fNotifyHandle <> THandle (-1) then FindCloseChangeNotification (fNotifyHandle);
  179.     Inherited Destroy;
  180. end;
  181.  
  182. procedure TWatchThread.Execute;
  183. var
  184.     ErrCode: Integer;
  185. begin
  186.     // Create the synchronisation object
  187.     fNotifyHandle := FindFirstChangeNotification (PChar (fOwner.fWatchDirectory), fOwner.fWatchSubtree, fOwner.WatchMask);
  188.     // No synchronisation object, no comment...
  189.     if fNotifyHandle <> THandle (-1) then while not Terminated do begin
  190.         ErrCode := WaitForSingleObject (fNotifyHandle, 250);
  191.         // Was it a timeout, or something more interesting ?
  192.         case ErrCode of
  193.              Wait_Timeout:   // Just a timeout -- ignore it....
  194.                  ;
  195.              Wait_Object_0:  // We've got a valid change notification
  196.                  begin
  197.                      Synchronize (fOwner.SignalFileNotification);
  198.                      FindNextChangeNotification (fNotifyHandle);
  199.                  end;
  200.  
  201.              else ;            // Something deeply bad has happened....
  202.         end;
  203.     end;
  204. end;
  205.  
  206. { TFileSystem }
  207.  
  208. constructor TFileSystem.Create (AOwner: TComponent);
  209. begin
  210.     Inherited Create (AOwner);
  211.     fFolders := TStringList.Create;
  212.     fFiles := TStringList.Create;
  213.     fFileTypes := [ftArchive];
  214.     fFolders.Sorted := True;
  215.     fFiles.Sorted := True;
  216.     SetDriveTypes ([fsFixed]);
  217.     fWatchMask := File_Notify_Change_File_Name or File_Notify_Change_Dir_Name;
  218. end;
  219.  
  220. destructor TFileSystem.Destroy;
  221. begin
  222.     // Kill the watch-thread first...
  223.     if fWatchThread <> Nil then SetWatchDirectory ('');
  224.     fFolders.Free;
  225.     fFiles.Free;
  226.     Inherited Destroy;
  227. end;
  228.  
  229. function TFileSystem.GetDriveCount: Integer;
  230. begin
  231.     Result := Length (fDrives);
  232. end;
  233.  
  234. function TFileSystem.GetDriveChar (Index: Integer): Char;
  235. begin
  236.     Result := #0;
  237.     if (Index >= 0) and (Index < Length (fDrives)) then Result := fDrives [Index + 1];
  238. end;
  239.  
  240. procedure TFileSystem.InitDrivesList;
  241. var
  242.     p: PChar;
  243.     Buff: array [0..255] of Char;
  244. begin
  245.     fDrives := '';
  246.     GetLogicalDriveStrings (sizeof (Buff), Buff);
  247.     p := Buff;
  248.     while p^ <> #0 do begin
  249.         if TDriveType (GetDriveType (p)) in fDriveTypes then begin
  250.             fDrives := fDrives + UpperCase (p^);
  251.             // If this is the first, make it the current drive by default.
  252.             if Length (fDrives) = 1 then SetDriveLetter (p^);
  253.         end;
  254.  
  255.         Inc (p, 4);
  256.     end;
  257. end;
  258.  
  259. function TFileSystem.GetUsedSpace: TLargeInteger;
  260. begin
  261.     Result := fTotalSize - fFreeSpace;
  262. end;
  263.  
  264. function TFileSystem.GetSerialNumber: String;
  265. begin
  266.     // Precision specifier in the format string ensures that leading zeroes
  267.     // actrually get printed instead of being silently discarded....
  268.     Result := Format ('%.4x-%.4x', [HiWord (fSerialNumber), LoWord (fSerialNumber)]);
  269. end;
  270.  
  271. procedure TFileSystem.SetDriveLetter (Value: Char);
  272. begin
  273.     Value := UpCase (Value);
  274.     if (Value <> fDriveLetter) and (Pos (Value, fDrives) > 0) then begin
  275.         fDriveLetter := Value;
  276.         fDriveType := TDriveType (GetDriveType (PChar (Value + ':\')));
  277.         Refresh;
  278.     end;
  279. end;
  280.  
  281. function TFileSystem.GetIsReady: Boolean;
  282. var
  283.     errMode, FindErr: Integer;
  284.     SearchRec: TSearchRec;
  285. begin
  286.     Result := fDriveType in [fsFixed, fsRemote, fsRAMDisk];
  287.     if not Result then begin
  288.         errMode := SetErrorMode (sem_FailCriticalErrors);
  289.         try
  290.             FindErr := FindFirst (fDriveLetter + ':\', faAnyFile, SearchRec);
  291.             try
  292.                 Result := FindErr = 2;
  293.             finally
  294.                 FindClose (SearchRec);
  295.             end;
  296.         finally
  297.             SetErrorMode (errMode);
  298.         end;
  299.     end;
  300. end;
  301.  
  302. procedure TFileSystem.SetDriveTypes (Value: TDriveTypes);
  303. begin
  304.     if Value <> fDriveTypes then begin
  305.         fDriveTypes := Value;
  306.         InitDrivesList;
  307.     end;
  308. end;
  309.  
  310. procedure TFileSystem.Refresh;
  311. var
  312.     Junk: DWord;
  313.     szVolumeName, szFileSystem: array [0..255] of char;
  314. begin
  315.     // Initialise drive-information properties
  316.     if not GetIsReady then raise EFileSystem.Create ('Drive not ready');
  317.     GetDiskFreeSpaceEx (PChar (fDriveLetter + ':\'), fAvailableSpace, fTotalSize, @fFreeSpace);
  318.     GetVolumeInformation (PChar (fDriveLetter + ':\'), szVolumeName, sizeof (szVolumeName),
  319.                           @fSerialNumber, Junk, Junk, szFileSystem, sizeof (szFileSystem));
  320.     fVolumeName := szVolumeName;
  321.     fFileSystem := szFileSystem;
  322.     SetFolderName ('');
  323. end;
  324.  
  325. procedure TFileSystem.SetVolumeName (Value: String);
  326. begin
  327.     if GetIsReady and (fVolumeName <> Value) then begin
  328.         if Length (Value) > 11 then Value := Copy (Value, 1, 11);
  329.         SetVolumeLabel (PChar (fDriveLetter + ':\'), PChar (Value));
  330.         Refresh; // Ensure fVolumeName reflects reality.....
  331.     end;
  332. end;
  333.  
  334. procedure TFileSystem.SetFolderName (Value: String);
  335. var
  336.     Idx: Integer;
  337. begin
  338.     // Do the trivial stuff first....
  339.     if Value = '.' then Exit;
  340.     if Value = '' then Value := fDriveLetter + ':\';
  341.  
  342.     // Handle a request to go up one level
  343.     if Value = '..' then begin
  344.        if Length (fFolderName) = 3 then Exit; // Already at root
  345.        Idx := Length (fFolderName) - 1;
  346.        while fFolderName [Idx] <> '\' do Dec (Idx);
  347.        Value := Copy (fFolderName, 1, Idx);
  348.     end;
  349.  
  350.     // Handle a relative path (no leading drive letter or backslash)
  351.     if (Value [1] <> '\') and (Value [2] <> ':') then Value := fFolderName + Value;
  352.  
  353.     // Handle an absolute path (no leading drive letter)
  354.     if Value [1] = '\' then Value := fDriveLetter + ':' + Value;
  355.  
  356.     // Handle a path -- with drive letter
  357.     if Value [2] = ':' then begin
  358.         Value [1] := UpCase (Value [1]);
  359.         if Value [1] <> fDriveLetter then Exit;
  360.         if Value [3] <> '\' then Value := fFolderName + Copy (Value, 3, MaxInt);
  361.     end;
  362.  
  363.     // At this point, Value should be in the form X:\YYYYYY
  364.     // Now, we need to check that the wanted path exists
  365.     if not DirectoryExists (Value) then Exit;
  366.  
  367.     // Finally, set the new folder name and refresh folder list
  368.     if Value [Length (Value)] <> '\' then Value := Value + '\';
  369.     if AnsiLowerCaseFileName (Value) <> AnsiLowerCaseFileName (fFolderName) then begin
  370.         fFolderName := Value;
  371.         RefreshFolderAndFileList;
  372.     end;
  373. end;
  374.  
  375. procedure TFileSystem.SetFileTypes (Value: TFileTypes);
  376. begin
  377.     if Value <> fFileTypes then begin
  378.         fFileTypes := Value;
  379.         RefreshFolderAndFileList;
  380.     end;
  381. end;
  382.  
  383. class function TFileSystem.DirectoryExists (const DirName: String): Boolean;
  384. var
  385.     OldDir: String;
  386. begin
  387.     OldDir := GetCurrentDir;
  388.     try
  389.         Result := SetCurrentDir (DirName);
  390.     finally
  391.         SetCurrentDir (OldDir);
  392.     end;
  393. end;
  394.  
  395. function TFileSystem.MatchingFile (Rec: TSearchRec): Boolean;
  396. begin
  397.     Result := True;
  398.     // Read-only file ?
  399.     if ((Rec.Attr and faReadOnly) <> 0) and (ftReadOnly in fFileTypes) then Exit;
  400.     // Hidden-file ?
  401.     if ((Rec.Attr and faHidden) <> 0) and (ftHidden in fFileTypes) then Exit;
  402.     // System-file ?
  403.     if ((Rec.Attr and faSysFile) <> 0) and (ftSystem in fFileTypes) then Exit;
  404.     // Archive file ?
  405.     if ((Rec.Attr and faArchive) <> 0) and (ftArchive in fFileTypes) then Exit;
  406.     Result := Rec.Attr = 0;
  407. end;
  408.  
  409. procedure TFileSystem.RefreshFolderAndFileList;
  410. var
  411.     Err: Integer;
  412.     Rec: TSearchRec;
  413. begin
  414.     fFolders.Clear;  fFiles.Clear;  fTotalFileSize := 0;
  415.     Err := FindFirst (fFolderName + '*.*', faAnyFile, Rec);
  416.     try
  417.        while Err = 0 do begin
  418.            if (Rec.Attr and faDirectory) <> 0 then begin
  419.                // Ignore the accursed '.' and '..' names
  420.                if Rec.Name [1] <> '.' then fFolders.Add (Rec.Name);
  421.            end else if (Rec.Attr and faVolumeID) = 0 then
  422.                // Not a directory, not a volumeID - must be a file!
  423.                if MatchingFile (Rec) then begin
  424.                    fFiles.Add (Rec.Name);
  425.                    fTotalFileSize := fTotalFileSize + Rec.Size;
  426.                end;
  427.  
  428.            Err := FindNext (Rec);
  429.        end;
  430.     finally
  431.         FindClose (Rec);
  432.     end;
  433. end;
  434.  
  435. procedure TFileSystem.TreeWalkFiles (Proc: TWalkProc);
  436. var
  437.     Continue: Boolean;
  438. begin
  439.     Screen.Cursor := crHourGlass;
  440.     try
  441.         Continue := True;
  442.         if Assigned (Proc) then FileWalker (fFolderName, Proc, Continue);
  443.     finally
  444.         Screen.Cursor := crDefault;
  445.     end;
  446. end;
  447.  
  448. procedure TFileSystem.TreeWalkFolders (Proc: TWalkProc);
  449. var
  450.     Continue: Boolean;
  451. begin
  452.     Screen.Cursor := crHourGlass;
  453.     try
  454.         Continue := True;
  455.         if Assigned (Proc) then FolderWalker (fFolderName, Proc, Continue);
  456.     finally
  457.         Screen.Cursor := crDefault;
  458.     end;
  459. end;
  460.  
  461. procedure TFileSystem.FileWalker (const Folder: String; Proc: TWalkProc; var Continue: Boolean);
  462. var
  463.     Err: Integer;
  464.     Rec: TSearchRec;
  465. begin
  466.     Err := FindFirst (Folder + '*.*', faAnyFile, Rec);
  467.     try
  468.        while (Err = 0) and Continue do begin
  469.            if (Rec.Attr and faDirectory) <> 0 then begin
  470.                // Ignore the accursed '.' and '..' names
  471.                if Rec.Name [1] <> '.' then FileWalker (Folder + Rec.Name + '\', Proc, Continue);
  472.            end else if (Rec.Attr and faVolumeID) = 0 then
  473.                // Not a directory, not a volumeID - must be a file!
  474.                if MatchingFile (Rec) then begin
  475.                    Proc (Folder + Rec.Name, Rec, Continue);
  476.                end;
  477.  
  478.            Err := FindNext (Rec);
  479.        end;
  480.     finally
  481.         FindClose (Rec);
  482.     end;
  483. end;
  484.  
  485. procedure TFileSystem.FolderWalker (const Folder: String; Proc: TWalkProc; var Continue: Boolean);
  486. var
  487.     Err: Integer;
  488.     Rec: TSearchRec;
  489. begin
  490.     Err := FindFirst (Folder + '*.*', faAnyFile, Rec);
  491.     try
  492.        while (Err = 0) and Continue do begin
  493.            if (Rec.Attr and faDirectory) <> 0 then begin
  494.                // Ignore the accursed '.' and '..' names
  495.                if Rec.Name [1] <> '.' then FileWalker (Folder + Rec.Name + '\', Proc, Continue);
  496.                Proc (Folder + Rec.Name + '\', Rec, Continue);
  497.            end;
  498.            Err := FindNext (Rec);
  499.        end;
  500.     finally
  501.         FindClose (Rec);
  502.     end;
  503. end;
  504.  
  505. procedure TFileSystem.SetWatchDirectory (const DirName: String);
  506. begin
  507.     if fWatchDirectory <> DirName then begin
  508.        fWatchDirectory := DirName;
  509.        if fWatchDirectory = '' then begin
  510.            // Stop watching...
  511.            fWatchThread.Terminate;
  512.            fWatchThread.WaitFor;
  513.            fWatchThread.Free;
  514.            fWatchThread := Nil;
  515.        end else
  516.            // Start watching...
  517.            if DirectoryExists (fWatchDirectory) then
  518.                fWatchThread := TWatchThread.Create (Self);
  519.     end;
  520. end;
  521.  
  522. procedure TFileSystem.SignalFileNotification;
  523. var
  524.     S1, S2: String;
  525.     fCurrent: Boolean;
  526. begin
  527.     if Assigned (fOnWatchDirChange) then begin
  528.         // See if we're actually pointing at the watched folder
  529.         S1 := fWatchDirectory;  if S1 [Length (S1)] <> '\' then S1 := S1 + '\';
  530.         S2 := fFolderName;      if S2 [Length (S2)] <> '\' then S2 := S2 + '\';
  531.         fCurrent := CompareText (S1, S2) = 0;
  532.         if fCurrent then RefreshFolderAndFileList;
  533.         fOnWatchDirChange (Self, fCurrent);
  534.     end;
  535. end;
  536.  
  537. //--------- End of TFileSystem component ---------------------------------
  538.  
  539. var
  540.     FileSys: TFileSystem;
  541.  
  542. procedure TForm1.FormCreate (Sender: TObject);
  543. var
  544.     Idx: Integer;
  545. begin
  546.     FileSys := TFileSystem.Create (Self);
  547.     with FileSys do begin
  548.         DriveTypes := [ fsFixed, fsRemote, fsCDROM ];
  549.         for Idx := 0 to DriveCount - 1 do DriveList.Items.Add (Drives [Idx] + ':');
  550.         DriveList.ItemIndex := 0;
  551.         DriveListChange (Self);
  552.         // Set File attribute checkboxes according to current 'FileTypes'
  553.         cbReadOnly.Checked := ftReadOnly in FileTypes;
  554.         cbHidden.Checked   := ftHidden in FileTypes;
  555.         cbSystem.Checked   := ftSystem in FileTypes;
  556.         cbArchive.Checked  := ftArchive in FileTypes;
  557.         // Set Watch stuff according to FileSystem
  558.         WatchSubs.Checked := WatchSubTree;
  559.     end;
  560. end;
  561.  
  562. procedure TForm1.FormDestroy(Sender: TObject);
  563. begin
  564.     FileSys.Free;
  565. end;
  566.  
  567. function TForm1.FormatBigBytes (const Msg: String; Value: TLargeInteger): String;
  568. var
  569.     Dbl: Double;
  570. begin
  571.      Dbl := Value;
  572.      Result := Format (Msg + ' %n', [Dbl]);
  573.      Result := Copy (Result, 1, Length (Result) - 3) + ' bytes';
  574. end;
  575.  
  576. procedure TForm1.DriveListChange(Sender: TObject);
  577. var
  578.     S: String;
  579.  
  580.     function StrDriveType (Typ: TDriveType): String;
  581.     begin
  582.         case Typ of
  583.           fsRemovable: Result := 'Removable';
  584.           fsFixed:     Result := 'Fixed    ';
  585.           fsRemote:    Result := 'Remote   ';
  586.           fsCDROM:     Result := 'CD-ROM   ';
  587.           fsRAMDisk:   Result := 'RAM-Disk ';
  588.           else         Result := '-unknown-';
  589.         end;
  590.     end;
  591.  
  592. begin
  593.     with FileSys do begin
  594.         // First, point TFileSystem object at the new drive
  595.         DriveLetter := DriveList.Text [1];
  596.         // Now display the various drive properties
  597.         VolSize.Caption := FormatBigBytes ('Total size of this drive is:', TotalSize);
  598.         S := VolumeName;  if S = '' then S := '[None]';
  599.         VolName.Caption := Format ('Volume label of this drive is: %s', [S]);
  600.         FSystem.Caption := Format ('File system of this drive is: %s', [FileSystem]);
  601.         SerNum.Caption := Format ('Serial number of this drive is: %s', [SerialNumber]);
  602.         DrvType.Caption := Format ('Type of this drive is: %s', [StrDriveType (DriveType)]);
  603.         FreeSp.Caption := FormatBigBytes ('Free space on this drive is:', FreeSpace);
  604.         UpdateFolderList ('');
  605.     end;
  606. end;
  607.  
  608. procedure TForm1.UpdateFolderList (const FolderName: String);
  609. begin
  610.     if FolderName <> '' then FileSys.FolderName := FolderName;
  611.     CurFolder.Text := FileSys.FolderName;
  612.     FolderList.Items.Assign (FileSys.Folders);
  613.     FolderList.ItemIndex := 0;
  614.     FileList.Items.Assign (FileSys.Files);
  615.     FileList.ItemIndex := 0;
  616.     FileCount.Caption := Format ('File count = %d', [FileList.Items.Count]);
  617.     TotFileSize.Caption := FormatBigBytes ('Total size of files is:', FileSys.TotalFileSize);
  618. end;
  619.  
  620. procedure TForm1.FolderListChange(Sender: TObject);
  621. begin
  622.     UpdateFolderList (FolderList.Text);
  623. end;
  624.  
  625. procedure TForm1.CurFolderKeyPress(Sender: TObject; var Key: Char);
  626. begin
  627.     if Key = #13 then UpdateFolderList (CurFolder.Text);
  628. end;
  629.  
  630. procedure TForm1.cbReadOnlyClick(Sender: TObject);
  631. var
  632.    ft: TFileType;
  633. begin
  634.     with Sender as TCheckBox do begin
  635.         ft := TFileType (Tag);
  636.         if Checked then FileSys.FileTypes := FileSys.FileTypes + [ft]
  637.         else FileSys.FileTypes := FileSys.FileTypes - [ft];
  638.         FileList.Items.Assign (FileSys.Files);
  639.         FileList.ItemIndex := 0;
  640.         FileCount.Caption := Format ('File count = %d', [FileList.Items.Count]);
  641.         TotFileSize.Caption := FormatBigBytes ('Total size of files is:', FileSys.TotalFileSize);
  642.     end;
  643. end;
  644.  
  645. procedure TForm1.SumProc (const Name: String; const Info: TSearchRec; var Continue: Boolean);
  646. begin
  647.     DirSize := DirSize + Info.Size;
  648. end;
  649.  
  650. procedure TForm1.Button1Click(Sender: TObject);
  651. begin
  652.     DirSize := 0;
  653.     FileSys.TreeWalkFiles (SumProc);
  654.     ShowMessage (FormatBigBytes ('Total size of this directory is:', DirSize));
  655. end;
  656.  
  657. procedure TForm1.WatchDirNameChange(Sender: TObject);
  658. begin
  659.     StartButton.Enabled := WatchDirName.Text <> '';
  660. end;
  661.  
  662. procedure TForm1.WatchDirChanged (Sender: TObject; CurrentFolder: Boolean);
  663. begin
  664.     if CurrentFolder then UpdateFolderList ('');
  665. end;
  666.  
  667. procedure TForm1.StartButtonClick(Sender: TObject);
  668. begin
  669.     // See if specified directory exists
  670.     if not FileSys.DirectoryExists (WatchDirName.Text) then ShowMessage ('Specified watch directory doesn''t exist!') else begin
  671.        FileSys.WatchSubtree := WatchSubs.Checked;
  672.        FileSys.OnWatchDirChange := WatchDirChanged;
  673.        FileSys.WatchDirectory := WatchDirName.Text;
  674.        StartButton.Enabled := False;
  675.        WatchDirName.Enabled := False;
  676.        StopButton.Enabled := True;
  677.     end;
  678. end;
  679.  
  680. procedure TForm1.StopButtonClick(Sender: TObject);
  681. begin
  682.     FileSys.WatchDirectory := '';
  683.     StopButton.Enabled := False;
  684.     StartButton.Enabled := True;
  685.     WatchDirName.Enabled := True;
  686. end;
  687.  
  688. procedure TForm1.WatchDirNameKeyPress(Sender: TObject; var Key: Char);
  689. begin
  690.     if Key = #13 then begin
  691.         StartButton.Click;
  692.         Key := #0;
  693.     end;
  694. end;
  695.  
  696. end.
  697.  
  698. autorefresh...
  699.  
  700.  
  701.  
  702.  
  703.  
  704.